home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / pop3serv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-06  |  26.0 KB  |  891 lines

  1. /* POP3 Server state machine - see RFC 1225
  2.  *
  3.  *      Jan 92  Erik Olson olson@phys.washington.edu
  4.  *              Taken from POP2 server code in NOS 910618
  5.  *              Rewritten/converted to POP3
  6.  *      Feb 92  William Allen Simpson
  7.  *              integrated with current work
  8.  *      Aug-Oct 92      Mike Bilow, N1BEE, mikebw@ids.net
  9.  *              Extensive bug fixes; changed uses of Borland stat()
  10.  *              to fsize() in order to fix intermittent crashes;
  11.  *              corrected confusion of sockmode()
  12.  *    November 93    KO4KS/Brian A. Lantz
  13.  *        Modified close_folder() for TNOS control files
  14.  *
  15.  *  "Need-to" list: XTND XMIT (to get WinQVTnet to work)
  16.  */
  17.  
  18. #include <stdio.h>
  19. #include <fcntl.h>
  20. #include <time.h>
  21. #include <sys/stat.h>
  22. #ifdef UNIX
  23. #include <sys/types.h>
  24. #endif
  25. #if     defined(__STDC__) || defined(__TURBOC__)
  26. #include <stdarg.h>
  27. #endif
  28. #include <ctype.h>
  29. #include <setjmp.h>
  30. #include "global.h"
  31. #include "mbuf.h"
  32. #include "cmdparse.h"
  33. #include "socket.h"
  34. #include "proc.h"
  35. #include "files.h"
  36. #include "mailbox.h"
  37. #include "bm.h"
  38. #include "smtp.h"
  39.  
  40. /* ---------------- common server data structures ---------------- */
  41. /* POP message pointer element */
  42.  
  43. struct pop_msg {
  44.         long len;
  45.         long pos;
  46.         int deleted;
  47.         struct pop_msg *next;
  48. };
  49.  
  50. /* POP server control block */
  51.  
  52. struct pop_scb {
  53.         int socket;             /* socket number for this connection */
  54.         char state;             /* server state */
  55. #define      LSTN       0
  56. #define      AUTH       1
  57. #define      TRANS      2
  58. #define      UPDATE     3
  59. #define      DONE       5
  60.  
  61.         char    buf[TLINELEN];   /* input line buffer */
  62.         char    count;          /* line buffer length */
  63.         char    username[64];   /* user/folder name */
  64.         FILE    *wf;            /* work folder file pointer */
  65.         int     folder_len;     /* number of msgs in current folder */
  66.         int     high_num;       /* highest message number accessed */
  67.         long    folder_file_size; /* length of the current folder file, in bytes */
  68.         char    folder_modified; /* mail folder contents modified flag */
  69.         struct pop_msg *msg;    /* message database link-list */
  70. };
  71.  
  72. #define NULLSCB  (struct pop_scb *)0
  73.  
  74. /* Response messages -- '\n' is converted to '\r\n' by the socket code */
  75.  
  76. static char     count_rsp[]     = "+OK you have %d messages\n",
  77.                 error_rsp[]     = "-ERR %s\n",
  78.                 greeting_msg[]  = "+OK %s POP3 ready\n",
  79.                 user_rsp[]      = "+OK user\n",
  80.                 pass_rsp[]      = "+OK password\n",
  81.                 stat_rsp[]      = "+OK %d %ld\n",
  82.                 list_single_rsp[]       = "+OK %d %d\n",
  83.                 list_multi_rsp[]        = "+OK %d messages (%ld octets)\n",
  84.                 retr_rsp[]      = "+OK %ld octets\n",
  85.                 multi_end_rsp[] = ".\n",
  86.                 msg_line[]      = "%s\n",
  87.                 dele_rsp[]      = "+OK message %d deleted\n",
  88.                 noop_rsp[]      = "+OK\n",
  89.                 last_rsp[]      = "+OK %d\n",
  90.                 signoff_msg[]   = "+OK Bye, bye-bye, bye now, goodbye\n";
  91.  
  92. static void rrip __ARGS((char *s));
  93. static struct pop_scb *create_scb __ARGS((void));
  94. static void delete_scb __ARGS((struct pop_scb *scb));
  95. static void popserv __ARGS((int s,void *unused,void *p));
  96. static int poplogin __ARGS((char *pass,char *username));
  97.  
  98. static void pop_sm __ARGS((struct pop_scb *scb));
  99.  
  100. static int Spop = -1; /* prototype socket for service */
  101.  
  102.  
  103. /* Start up POP receiver service */
  104. int
  105. pop3start(argc,argv,p)
  106. int argc;
  107. char *argv[];
  108. void *p;
  109. {
  110.     return (installserver (argc, argv, &Spop, "POP3 listener", IPPORT_POP3,
  111.         "POP3 server", popserv, 2048, NULL));
  112. }
  113.  
  114. /* Shutdown POP3 service (existing connections are allowed to finish) */
  115.  
  116. int
  117. pop3stop(argc,argv,p)
  118. int argc;
  119. char *argv[];
  120. void *p;
  121. {
  122.     return (deleteserver (&Spop));
  123. }
  124.  
  125. static void
  126. popserv(s,unused,p)
  127. int s;
  128. void *unused;
  129. void *p;
  130. {
  131.         struct pop_scb *scb;
  132.  
  133.         sockowner(s,Curproc);           /* We own it now */
  134.         log(s,"open POP3");
  135.  
  136.         if((scb = create_scb()) == NULLSCB) {
  137.                 tprintf(Nospace);
  138.                 log(s,"close POP3 - no space");
  139.                 close_s(s);
  140.                 return;
  141.         }
  142.  
  143.         scb->socket = s;
  144.         scb->state  = AUTH;
  145.  
  146.         sockmode(s,SOCK_ASCII);         /* N1BEE */
  147.         (void) usprintf(s,greeting_msg,Hostname);
  148.  
  149. loop:   if ((scb->count = recvline(s,scb->buf,TLINELEN)) == -1){
  150.                 /* He closed on us */
  151.  
  152.                 goto quit;
  153.         }
  154.  
  155.         rip(scb->buf);
  156.         if (strlen(scb->buf) == 0)      /* Ignore blank cmd lines */
  157.                 goto loop;
  158.         pop_sm(scb);
  159.         if (scb->state == DONE)
  160.                 goto quit;
  161.  
  162.         goto loop;
  163.  
  164. quit:
  165.         log(scb->socket,"close POP3");
  166.         close_s(scb->socket);
  167.         delete_scb(scb);
  168. }
  169.  
  170.  
  171. /* Create control block, initialize */
  172.  
  173. static struct
  174. pop_scb *create_scb()
  175. {
  176.         register struct pop_scb *scb;
  177.  
  178.         if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULLSCB)
  179.                 return NULLSCB;
  180.  
  181.         scb->username[0] = '\0';
  182.         scb->msg = NULL;
  183.         scb->wf = NULL;
  184.  
  185.         scb->count = scb->folder_file_size = 0;
  186.  
  187.         scb->folder_modified = FALSE;
  188.         return scb;
  189. }
  190.  
  191.  
  192. /* Free msg link-list */
  193. static void
  194. delete_msglist(b_msg)
  195. struct pop_msg *b_msg;
  196. {
  197.         struct pop_msg *msg,*msg2;
  198.         msg=b_msg;
  199.         while(msg!=NULL) {msg2=msg->next; free(msg); msg=msg2;}
  200. }
  201.  
  202. /* Free resources, delete control block */
  203.  
  204. static void
  205. delete_scb(scb)
  206. register struct pop_scb *scb;
  207. {
  208.         if (scb == NULLSCB)
  209.                 return;
  210.         if (scb->wf != NULL)
  211.                 fclose(scb->wf);
  212.         if (scb->msg  != NULL)
  213.                 delete_msglist(scb->msg);
  214.  
  215.         free((char *)scb);
  216. }
  217.  
  218. /* replace terminating end of line marker(s) (\r and \n) with null,
  219.                         and change . to .. */
  220. static void
  221. rrip(s)
  222. register char *s;
  223. {
  224.         register char *cp;
  225.  
  226.         if((cp = strchr(s,'\r')) != NULLCHAR)
  227.                 *cp = '\0';
  228. #ifndef TNOS_68K
  229.     if((cp = strchr(s,'\n')) != NULLCHAR)
  230. #else
  231.     if((cp = strchr(s,'\l')) != NULLCHAR)
  232. #endif
  233.                 *cp = '\0';
  234. }
  235.  
  236. /* --------------------- start of POP server code ------------------------ */
  237.  
  238. #define BITS_PER_WORD   16
  239.  
  240. #define isSOM(x)        ((strncmp(x,"From ",5) == 0))
  241.  
  242. /* Command string specifications */
  243.  
  244. static char
  245.                 user_cmd[] = "USER ",
  246.                 pass_cmd[] = "PASS ",
  247.                 quit_cmd[] = "QUIT",
  248.                 stat_cmd[] = "STAT",
  249.                 list_cmd[] = "LIST",
  250.                 retr_cmd[] = "RETR",
  251.                 dele_cmd[] = "DELE",
  252.                 noop_cmd[] = "NOOP",
  253.                 rset_cmd[] = "RSET",
  254.                 top_cmd[]  = "TOP",
  255.                 last_cmd[] = "LAST";
  256.  
  257. static void
  258. pop_sm(scb)
  259. struct pop_scb *scb;
  260. {
  261.         char password[40];
  262.  
  263.         void state_error __ARGS((struct pop_scb *,char *));
  264.         void fatal_error __ARGS((struct pop_scb *,char *));
  265.         void open_folder __ARGS((struct pop_scb *));
  266.         void do_cleanup __ARGS((struct pop_scb *));
  267.         void stat_message __ARGS((struct pop_scb *));
  268.         void list_message __ARGS((struct pop_scb *));
  269.         void retr_message __ARGS((struct pop_scb *));
  270.         void dele_message __ARGS((struct pop_scb *));
  271.         void noop_message __ARGS((struct pop_scb *));
  272.         void last_message __ARGS((struct pop_scb *));
  273.         void rset_message __ARGS((struct pop_scb *));
  274.         void top_message __ARGS((struct pop_scb *));
  275.         void close_folder __ARGS((struct pop_scb *));
  276.  
  277.         if (scb == NULLSCB) /* be certain it is good -- wa6smn */
  278.                 return;
  279.  
  280.         switch(scb->state) {
  281.  
  282.         case AUTH:
  283.                 if (strncmp(scb->buf,user_cmd,strlen(user_cmd)) == 0){
  284.                         sscanf(scb->buf,"USER %s",scb->username);
  285.                         (void) usprintf(scb->socket,user_rsp);
  286.  
  287.                 } else if (strncmp(scb->buf,pass_cmd,strlen(pass_cmd)) == 0){
  288.                         sscanf(scb->buf,"PASS %s",password);
  289.  
  290.                         if (!poplogin(scb->username,password)) {
  291.                                 log(scb->socket,"POP3 access DENIED to %s",
  292.                                                 scb->username);
  293.                                 state_error(scb,"Access DENIED!!");
  294.                                 return;
  295.                         }
  296.  
  297.                         log(scb->socket,"POP3 access granted to %s",
  298.                                         scb->username);
  299.                         open_folder(scb);
  300.                 } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
  301.                         do_cleanup(scb);
  302.                 } else
  303.                         state_error(scb,"(AUTH) expected USER, PASS or QUIT");
  304.                 break;
  305.  
  306.         case TRANS:
  307.                 if (strncmp(scb->buf,stat_cmd,strlen(stat_cmd)) == 0)
  308.                         stat_message(scb);
  309.  
  310.                 else if (strncmp(scb->buf,list_cmd,strlen(list_cmd)) == 0)
  311.                         list_message(scb);
  312.  
  313.                 else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
  314.                         retr_message(scb);
  315.  
  316.                 else if (strncmp(scb->buf,dele_cmd,strlen(dele_cmd)) == 0)
  317.                         dele_message(scb);
  318.  
  319.                 else if (strncmp(scb->buf,last_cmd,strlen(noop_cmd)) == 0)
  320.                         noop_message(scb);
  321.  
  322.                 else if (strncmp(scb->buf,last_cmd,strlen(last_cmd)) == 0)
  323.                         last_message(scb);
  324.  
  325.                 else if (strncmp(scb->buf,top_cmd,strlen(top_cmd)) == 0)
  326.                         top_message(scb);
  327.  
  328.                 else if (strncmp(scb->buf,rset_cmd,strlen(rset_cmd)) == 0)
  329.                         rset_message(scb);
  330.  
  331.                 else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
  332.                         do_cleanup(scb);
  333.  
  334.                 else
  335.                         state_error(scb,
  336.                                         "(TRANS) unsupported/unrecognized command");
  337.                 break;
  338.  
  339.         case DONE:
  340.                 break;
  341.  
  342.         default:
  343.                 fatal_error(scb,"(TOP) State Error!!");
  344.                 break;
  345.         }
  346. }
  347.  
  348. static void
  349. do_cleanup(scb)
  350. struct pop_scb *scb;
  351. {
  352.         void close_folder __ARGS((struct pop_scb *));
  353.  
  354.         close_folder(scb);
  355.         (void) usprintf(scb->socket,signoff_msg);
  356.         scb->state = DONE;
  357. }
  358.  
  359. static void
  360. state_error(scb,msg)
  361. struct pop_scb *scb;
  362. char *msg;
  363. {
  364.         (void) usprintf(scb->socket,error_rsp,msg);
  365.         /* scb->state = DONE; */  /* Don't automatically hang up */
  366. }
  367.  
  368. static void
  369. fatal_error(scb,msg)
  370. struct pop_scb *scb;
  371. char *msg;
  372. {
  373.         (void) usprintf(scb->socket,error_rsp,msg);
  374.         scb->state = DONE;
  375. }
  376.  
  377. static void
  378. close_folder(scb)
  379. struct pop_scb *scb;
  380. {
  381.         char folder_pathname[64];
  382.         char line[TLINELEN+1];
  383.         FILE *fd;
  384.         int deleted = FALSE;
  385.         int msg_no = 0;
  386.         struct pop_msg *msg;
  387.         int newmail __ARGS((struct pop_scb *));
  388.         void state_error __ARGS((struct pop_scb *,char *));
  389.         void fatal_error __ARGS((struct pop_scb *,char *));
  390.     char *cp;
  391.     int firstIDline = 0, nextisBID = 0, k;
  392.     int lines = 0;
  393.     long last;
  394.     struct let lt;
  395.  
  396.  
  397.         if (scb->wf == NULL)
  398.                 return;
  399.  
  400.         if (!scb->folder_modified) {
  401.                 /* no need to re-write the folder if we have not modified it */
  402.  
  403.                 fclose(scb->wf);
  404.                 scb->wf = NULL;
  405.  
  406.                 delete_msglist(scb->msg);
  407.                 scb->msg=NULL;
  408.                 return;
  409.         }
  410.  
  411.  
  412.         sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  413.  
  414.         if (newmail(scb)) {
  415.                 /* copy new mail into the work file and save the
  416.                                         message count for later */
  417.  
  418.                 if ((fd = fopen(folder_pathname,"r")) == NULL) {
  419.                         fatal_error(scb,"Unable to add new mail to folder");
  420.                         return;
  421.                 }
  422.  
  423.                 fseek(scb->wf,0,SEEK_END);
  424.                 fseek(fd,scb->folder_file_size,SEEK_SET);
  425.                 while (!feof(fd)) {
  426.                         fgets(line,TLINELEN,fd);
  427.                         fputs(line,scb->wf);
  428.                 }
  429.  
  430.                 fclose(fd);
  431.         }
  432.  
  433.         /* now create the updated mail folder */
  434.  
  435.         if ((fd = fopen(folder_pathname,"w")) == NULL){
  436.                 fatal_error(scb,"Unable to update mail folder");
  437.                 return;
  438.         }
  439.  
  440.         rewind(scb->wf);
  441.  
  442.     sprintf(line,"%s/CONTROL/%s.ctl",Mailspool,scb->username);
  443.     remove (line);
  444.     lt.start = last = 0;
  445.  
  446.         msg=scb->msg;
  447.         while (!feof(scb->wf)){
  448.                 fgets(line,TLINELEN,scb->wf);
  449.                 if (feof(scb->wf))
  450.                     continue;
  451.         pwait(NULL);    /* give other processes time in long copy */
  452.  
  453.                 if (isSOM(line)){
  454.             lt.size = last - lt.start - lines; 
  455.             if (lt.size && (deleted == FALSE))
  456.                 updateCtl (scb->username, <);
  457.             lines = lt.status = 0;
  458.             lt.start = last;
  459.             firstIDline = 0;
  460.  
  461.                         if (msg!=NULL) msg=msg->next;
  462.                         msg_no++;
  463.                         if (msg!=NULL)
  464.                                 deleted = msg->deleted;
  465.                         else
  466.                                 deleted = FALSE;
  467.                 }
  468.  
  469.         lines++;
  470.         if (!firstIDline && nextisBID && (cp=strstr(line,"AA")) != NULLCHAR) {
  471.             /*what follows is the message-number*/
  472.             lt.bid = atol(cp+2);
  473.             nextisBID = 0;
  474.             firstIDline = 1;
  475.             }
  476.  
  477.         if (!strncmp ("Received: ", line, 10))
  478.             nextisBID = 1;
  479.         if (!strncmp ("Status: R", line, 9))
  480.             lt.status = BM_READ;
  481.  
  482.                 if (deleted)
  483.                         continue;
  484.  
  485.                 fputs(line,fd);
  486.         last = ftell (fd);
  487.         }
  488.     lt.size = last - lt.start - lines;
  489.     if (deleted == FALSE)
  490.         updateCtl (scb->username, <);
  491.  
  492.         fclose(fd);
  493.         fclose(scb->wf);
  494.         scb->wf = NULL;
  495.         delete_msglist(scb->msg);
  496.         scb->msg=NULL;
  497.  
  498. }
  499.  
  500. static void
  501. open_folder(scb)
  502. struct pop_scb *scb;
  503. {
  504.         char folder_pathname[64];
  505.         char line[TLINELEN];
  506.         long pos;
  507.         FILE *fd;
  508.         FILE *tmpfile();
  509.         struct stat folder_stat;
  510.         struct pop_msg *msg;
  511.  
  512.         sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  513.         scb->folder_len       = 0;
  514.         scb->folder_file_size = 0;
  515.         /* if (stat(folder_pathname,&folder_stat)){ */
  516.         if((folder_stat.st_size = fsize(folder_pathname)) == -1) { /* N1BEE */
  517.                 (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  518.                 scb->state  = TRANS;
  519.                 return;         /* no file = OK */
  520.         }
  521.  
  522.         scb->folder_file_size = folder_stat.st_size;
  523.         if ((fd = fopen(folder_pathname,"r")) == NULL){
  524.                 state_error(scb,"Unable to open mail folder");
  525.                 return;
  526.         }
  527.  
  528.         if ((scb->wf = tmpfile()) == NULL) {
  529.                 state_error(scb,"Unable to create work folder");
  530.                 return;
  531.         }
  532.  
  533.         scb->msg=calloc(sizeof(struct pop_msg),1); /* create first element */
  534.         if (scb->msg==NULL)
  535.         {
  536.                 fatal_error(scb,"Unable to create pointer list");
  537.                 return;
  538.         }
  539.         scb->msg->next=NULL;
  540.         msg=scb->msg;
  541.         msg->len=0;
  542.         msg->deleted=0;
  543.  
  544.         while(!feof(fd)) {
  545.                 pos=ftell(scb->wf);
  546.                 fgets(line,TLINELEN,fd);
  547.  
  548.                 /* scan for begining of a message */
  549.  
  550.                 if (isSOM(line))
  551.                 {
  552.                         scb->folder_len++;
  553.                         msg->next=calloc(sizeof(struct pop_msg),1);
  554.                         if (msg->next==NULL)
  555.                         {
  556.                                 fatal_error(scb,
  557.                                                 "Unable to create pointer list")
  558. ;
  559.                                 return;
  560.                         }
  561.                         msg=msg->next;
  562.                         msg->pos=pos;
  563.                         msg->next=NULL;
  564.                         msg->len=0;
  565.                         msg->deleted=0;
  566.  
  567.                 /* now put  the line in the work file */
  568.                 }
  569.                 fputs(line,scb->wf);
  570.                 rrip(line);
  571.                 if ( *line == '.' ) msg->len++;
  572.                 msg->len +=strlen(line)+2; /* Add msg len count */
  573.         }
  574.  
  575.         fclose(fd);
  576.         scb->high_num=0;  /* reset high read */
  577.  
  578.         (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  579.  
  580.         scb->state  = TRANS;
  581. }
  582.  
  583. static void
  584. stat_message(scb)
  585. struct pop_scb *scb;
  586. {
  587.         long total=0;
  588.         int count=0;
  589.         struct pop_msg *msg;
  590.  
  591.         if (scb == NULLSCB) /* check for null -- wa6smn */
  592.                 return;
  593.  
  594.         if (scb->folder_len)    /* add everything up */
  595.                 for (msg=scb->msg->next; msg!=NULL; msg=msg->next)
  596.                         if (!msg->deleted)
  597.                                 {       total += msg->len; ++count;}
  598.  
  599.         (void) usprintf(scb->socket,stat_rsp,count,total);
  600. }
  601.  
  602. static void
  603. list_message(scb)
  604. struct pop_scb *scb;
  605. {
  606.         struct pop_msg *msg;
  607.         int msg_no=0;
  608.         long total=0;
  609.         struct pop_msg *goto_msg __ARGS((struct pop_scb *,int ));
  610.  
  611.         if (scb == NULLSCB) /* check for null -- wa6smn */
  612.                 return;
  613.         if (scb->buf[sizeof(list_cmd) - 1] == ' ')
  614.         {
  615.                 msg_no = atoi(&(scb->buf[sizeof(list_cmd) - 1]));
  616.                 msg=goto_msg(scb,msg_no);
  617.                 if (msg==NULL || msg->deleted)
  618.                         state_error(scb,"non existent or deleted message");
  619.                 else
  620.                         (void) usprintf(scb->socket,list_single_rsp,
  621.                         msg_no,msg->len);
  622.         } else  /* multiline */
  623.         {
  624.                 if (scb->folder_len)            /* add everything */
  625.                         for (msg=scb->msg->next; msg!=NULL;msg=msg->next)
  626.                                 if (!msg->deleted)
  627.                 total += msg->len,++msg_no;
  628.  
  629.                 (void) usprintf(scb->socket,list_multi_rsp,
  630.                                 msg_no,total);
  631.  
  632.                 if (scb->folder_len)
  633.                         for (msg=scb->msg->next,msg_no=1; msg!=NULL;
  634.                                         msg=msg->next,msg_no++)
  635.                                 if (!msg->deleted) {
  636.                                         (void) usprintf(scb->socket,"%d %ld\n",
  637.                                                 msg_no,msg->len);
  638.                                 }
  639.                 (void) usprintf(scb->socket,multi_end_rsp);
  640.         }
  641. }
  642.  
  643. static void
  644. retr_message(scb)
  645. struct pop_scb *scb;
  646. {
  647.         char line[TLINELEN];
  648.         long cnt;
  649.         int msg_no;
  650.         struct pop_msg *msg;
  651.         struct pop_msg *goto_msg __ARGS((struct pop_scb *,int ));
  652.  
  653.         if (scb == NULLSCB) /* check for null -- wa6smn */
  654.                 return;
  655.         if (scb->buf[sizeof(retr_cmd) - 1] != ' ')
  656.         {
  657.                 state_error(scb,"no such message");
  658.                 return;
  659.         }
  660.         msg_no = atoi(&(scb->buf[sizeof(retr_cmd) - 1]));
  661.         msg=goto_msg(scb,msg_no);
  662.         if (msg==NULL || msg->deleted) {
  663.                 state_error(scb,"no such message");
  664.                 return;
  665.         }
  666.  
  667.         cnt  = msg->len;
  668.         (void) usprintf(scb->socket,retr_rsp,cnt);
  669.         fseek(scb->wf,msg->pos,SEEK_SET);  /* Go there */
  670.  
  671.         while(!feof(scb->wf) && (cnt > 0)) {
  672.                 fgets(line,TLINELEN,scb->wf);
  673.                 rrip(line);
  674.                 if ( *line == '.' ) {
  675.                         (void) usprintf(scb->socket,".");
  676.                         cnt--;
  677.                 }
  678.                 (void) usprintf(scb->socket,msg_line,line);
  679.                 cnt -= (strlen(line)+2); /* Compensate for CRLF */
  680.         }
  681.         (void) usprintf(scb->socket,".\n");
  682.         if (msg_no >= scb->high_num)
  683.                 scb->high_num=msg_no;     /* bump high water mark */
  684. }
  685.  
  686. static void
  687. noop_message(scb)
  688. struct pop_scb *scb;
  689. {
  690.                 (void) usprintf(scb->socket,noop_rsp);
  691. }
  692.  
  693. static void
  694. last_message(scb)
  695. struct pop_scb *scb;
  696. {
  697.         (void) usprintf(scb->socket,last_rsp,scb->high_num);
  698. }
  699.  
  700. static void
  701. rset_message(scb)
  702. struct pop_scb *scb;
  703. {
  704.         struct pop_msg *msg;
  705.         long total=0;
  706.  
  707.         if (scb->folder_len)
  708.                 for (msg=scb->msg->next; msg!=NULL; msg=msg->next)
  709.                         msg->deleted=FALSE,total+=msg->len;
  710.  
  711.         scb->high_num=0;  /* reset last */
  712.         scb->folder_modified=FALSE;
  713.         (void) usprintf(scb->socket,list_multi_rsp,scb->folder_len,total);
  714. }
  715.  
  716. static void
  717. top_message(scb)
  718. struct pop_scb *scb;
  719. {
  720.         char *ptr;
  721.         char line[TLINELEN];
  722.         struct pop_msg *msg;
  723.         int msg_no=0,lines=0;
  724.         long total=0;
  725.  
  726.         struct pop_msg *goto_msg __ARGS((struct pop_scb *,int ));
  727.  
  728.         if (scb == NULLSCB) /* check for null -- wa6smn */
  729.                 return;
  730.         if (scb->buf[sizeof(top_cmd) - 1] != ' ')
  731.         {
  732.                 state_error(scb,"No message specified");
  733.                 return;
  734.         }
  735.         for (ptr=scb->buf+sizeof(top_cmd); *ptr==' ' ; ++ptr);
  736.                 /* Space drop */
  737.         for ( ; *ptr!=' ' && *ptr !='\0'; ++ptr);
  738.                 /* token drop */
  739.         msg_no = atoi(&(scb->buf[sizeof(top_cmd) - 1]));
  740.         lines = atoi(++ptr);  /* Get # lines to top */
  741.         if (lines < 0) lines=0;
  742.  
  743.         msg=goto_msg(scb,msg_no);
  744.         if (msg==NULL || msg->deleted)
  745.         {
  746.                 state_error(scb,"non existent or deleted message");
  747.                 return;
  748.         }
  749.         fseek(scb->wf,msg->pos,SEEK_SET);  /* Go there */
  750.         total=msg->len;  /* Length of current message */
  751.         (void) usprintf(scb->socket,noop_rsp);  /* Give OK */
  752.         do {
  753.                 fgets(line,TLINELEN,scb->wf);
  754.                 rrip(line);
  755.                 if ( *line == '.' ) {
  756.                         (void) usprintf(scb->socket,".");
  757.                         total--;
  758.                 }
  759.                 total -= strlen(line)+2;
  760.                 (void) usprintf(scb->socket,msg_line,line);
  761.         } while (*line!='\0' && total>0);
  762.         for ( ; total > 0 && lines; --lines) {
  763.                 fgets(line,TLINELEN,scb->wf);
  764.                 rrip(line);
  765.                 if ( *line == '.' ) {
  766.                         (void) usprintf(scb->socket,".");
  767.                         total--;
  768.                 }
  769.                 total -= strlen(line)+2;
  770.                 (void) usprintf(scb->socket,msg_line,line);
  771.         }
  772.         (void) usprintf(scb->socket,multi_end_rsp);
  773. }
  774.  
  775. static int
  776. poplogin(username,pass)
  777. char *pass;
  778. char *username;
  779. {
  780.         char buf[80];
  781.         char *cp;
  782.         char *cp1;
  783.         FILE *fp;
  784.  
  785.         if((fp = fopen(Popusers,"r")) == NULLFILE) {
  786.                 /* User file doesn't exist */
  787.                 tprintf("POP users file %s not found\n",Popusers);
  788.                 return(FALSE);
  789.         }
  790.  
  791.         while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
  792.                 if(buf[0] == '#')
  793.                         continue; /* Comment */
  794.  
  795.                 if((cp = strchr(buf,':')) == NULLCHAR)
  796.                         /* Bogus entry */
  797.                         continue;
  798.  
  799.                 *cp++ = '\0';  /* Now points to password */
  800.                 if(strcmp(username,buf) == 0)
  801.                         break;  /* Found user name */
  802.         }
  803.  
  804.         if(feof(fp)) {
  805.                 /* User name not found in file */
  806.  
  807.                 fclose(fp);
  808.                 return(FALSE);
  809.         }
  810.         fclose(fp);
  811.  
  812.         if ((cp1 = strchr(cp,':')) == NULLCHAR)
  813.                 return(FALSE);
  814.  
  815.         *cp1 = '\0';
  816.         if(strcmp(cp,pass) != 0) {
  817.                 /* Password required, but wrong one given */
  818.  
  819.                 return(FALSE);
  820.         }
  821.  
  822.         /* whew! finally made it!! */
  823.  
  824.         return(TRUE);
  825. }
  826.  
  827. static void
  828. dele_message(scb)
  829. struct pop_scb *scb;
  830. {
  831.         struct pop_msg *msg;
  832.         int msg_no;
  833.         struct pop_msg *goto_msg __ARGS((struct pop_scb *,int ));
  834.  
  835.         if (scb == NULLSCB) /* check for null -- wa6smn */
  836.                 return;
  837.         if (scb->buf[sizeof(retr_cmd) - 1] != ' ')
  838.         {
  839.                 state_error(scb,"no such message");
  840.                 return;
  841.         }
  842.         msg_no = atoi(&(scb->buf[sizeof(retr_cmd) - 1]));
  843.         msg=goto_msg(scb,msg_no);
  844.         if (msg==NULL || msg->deleted) {
  845.                 state_error(scb,"attempt to access deleted message");
  846.                 return;
  847.         }
  848.         if (msg->deleted) /* Don't bother if already dead */
  849.         {
  850.                         state_error(scb,"message already deleted");
  851.                         return;
  852.         }
  853.         msg->deleted=TRUE;
  854.         scb->folder_modified = TRUE;
  855.         (void) usprintf(scb->socket,dele_rsp,msg_no);
  856. }
  857.  
  858. static int
  859. newmail(scb)
  860. struct pop_scb *scb;
  861. {
  862.         char folder_pathname[64];
  863.         struct stat folder_stat;
  864.  
  865.         sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  866.  
  867.         /* if (stat(folder_pathname,&folder_stat)) { */
  868.         if((folder_stat.st_size = fsize(folder_pathname)) == -1) { /* N1BEE */
  869.                 state_error(scb,"Unable to get old mail folder's status");
  870.                 return(FALSE);
  871.         } else
  872.                 return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
  873. }
  874.  
  875. static struct pop_msg *
  876. goto_msg(scb,msg_no)
  877. struct pop_scb *scb;
  878. int msg_no;
  879. {
  880.         int msg_num;
  881.         struct pop_msg *msg;
  882.  
  883.         msg_num=msg_no-1;
  884.         if (scb->folder_len==0 || msg_num < 0)
  885.                         return NULL;
  886.         for (msg=scb->msg->next; msg_num && msg!=NULL; --msg_num) msg=msg->next;
  887.         return msg;
  888. }
  889.  
  890.  
  891.